#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>




#include <sys/shm.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>
#include <features.h>

union semun {
    int             val;
    struct          semid_ds *buf;
    unsigned short  *array;
};


static void* write_to_pipe(void* arg1);
static void* read_from_pipe(void* arg2);

int main()
{
    int          pip_fd[2];
    int          status=0;
    char         string[200]="Ping";
    char         stread[2]="\0";
    pthread_t    thread[2];

    void*        arg1[5];
    void*        arg2[5];
    int          i=0;
/*    pthread_condattr_t     attr_t;*/

    pthread_mutex_t         mutex;
/*    pthread_mutex_t         mutex2;*/
    pthread_cond_t          cond1;
/*    pthread_cond_t          cond2;*/
    pthread_mutexattr_t    attr;

    pthread_cond_init(&cond1,0);
/*    pthread_cond_init(&cond2,0);*/


/*    thread_condattr_init(&attr );*/



/*    pthread_condattr_setname ( pthread_condattr_t *attr_t, Type t)*/



    /*initiallyzinf the mutex attribute its a parameter determinds the type of mutex*/
    if(pthread_mutexattr_init(&attr))
    {
        return 1;
    }

    /*Able to lock mutex number times without unlock*/
    if(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
    {
        return 1;
    }

    /*Optin allows to share the mutex be shared beween process*/
    if( pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED))
    {
        return 1;
    }
    if(pthread_mutex_init(&(mutex) ,&attr ))
    {
        return 1;
    }


  /* key_t        key;
    int          semID;
    union semun     semu;
    semu.val   =     1;


    key = ftok("/home/seriygena/Documents/Projects/PingPong/main.c",1);
    semID = semget(key,1, 0666 | IPC_CREAT | IPC_EXCL);
    status=semctl(semID,0,SETVAL,semu);*/


    pipe(pip_fd);

    arg1[0]= string;
    arg1[1]= &status;
    arg1[2]= &pip_fd[1];
    arg1[3]= &(mutex);
    arg1[4]= &cond1;


    arg2[0]= stread;
    arg2[1]= &status;
    arg2[2]= &pip_fd[0];
    arg2[3]= &(mutex);
    arg2[4]= &(cond1);

   /* for(i=0;i<10000;++i)
    {*/
        pthread_create( &thread[0], NULL, write_to_pipe, arg1);
        pthread_create( &thread[1], NULL, read_from_pipe,arg2);
    /*}*/

    pthread_join(thread[0], NULL);

    exit(EXIT_SUCCESS);
}


void* write_to_pipe(void* arg1)
{
    char*   _string =(char*) ((void**)arg1)[0];
    int*    _status =(int*)  ((void**)arg1)[1];
    int*    _pipw    =(int*)  ((void**)arg1)[2];

    char*    pongstr="pong";
    int      count=0;

   /* int*     _semID   =(int*)   ((void**)arg1)[3];*/
   pthread_mutex_t*  _mutex=(pthread_mutex_t*)   ((void**)arg1)[3];
   pthread_cond_t*  _cond= (pthread_cond_t*)((void**)arg1)[4];

   /*Locking semaphore for writing*
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1; * -1 it meens decrement the value by 1 *
    sem_b.sem_flg = SEM_UNDO;*Flag for operation system*

    if (semop(*_semID, &sem_b, 1) == -1)
    {
        fprintf(stderr,"\nsemaphore lock failed\n");
    }*/

    while(count < 10)
    {

           pthread_mutex_lock(_mutex);
           pthread_cond_wait(_cond,_mutex);
           pthread_mutex_unlock(_mutex );
           pthread_mutex_lock(_mutex);
           write(*_pipw,pongstr,strlen( pongstr));
           printf("%s ",_string);
           ++count;
    }

     /*      if (!pthread_cond_wait(_cond,_mutex ))
           {

           }
           pthread_mutex_unlock(_mutex);
           pthread_cond_signal(_cond);
       }*/

/* Unlock semphore
    sem_b.sem_num = 0;
    sem_b.sem_op = 1; * 1 it meens increment the value by 1 *
    sem_b.sem_flg = SEM_UNDO;*Flag for operation system*

    if (semop(*_semID, &sem_b, 1) == -1)
    {
        fprintf(stderr,"semaphore Unlock failed\n");
    }*/
/*    ++*_status;*/

    return (void*)0;
}

void* read_from_pipe(void* arg2)
{
        char*   _string =(char*) ((void**)arg2)[0];
        int*    _pipr    =(int*) ((void**)arg2)[2];
       int      count=0;
      /*  int*     _semID   =(int*)   ((void**)arg2)[3];*/

    pthread_mutex_t*  _mutex=(pthread_mutex_t*)   ((void**)arg2)[3];
    pthread_cond_t*  _cond= (pthread_cond_t*)((void**)arg2)[4];


/*       pthread_mutex_lock(_mutex);*/



      /* while(read(*_pipr,_string,1)>0)
       {
          printf("%s",_string);
          fflush(stdout);
       }*/

       while (count<10)
       {
           pthread_mutex_lock(_mutex);
           pthread_cond_signal(_cond);
           pthread_mutex_unlock(_mutex );
           pthread_mutex_lock(_mutex);
           /*write(*_pipr,pongstr,strlen( pongstr));*/
           printf("%s ", "pong");
           ++count;

     /*      if ( pthread_cond_signal(_cond))
           {
                printf("%s ", "pong");
                pthread_cond_signal(_cond);
                ++count;
           }
           pthread_mutex_unlock(_mutex);*/
       }
       return (void*)0;
}
